/*
 * @Author: your name
 * @Date: 2020-05-07 14:15:21
 * @LastEditTime: 2020-07-23 09:00:15
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \truck\platform\space_mgnt\file_space.c
 */
#include "global_common.h"
#include "file_space.h"
#include "xeSqlite.h"



static int _xsd_rec_disk_num = 0;
static int _xsd_rec_disk_scaned = 0;
xerec_disk_t *_xsd_rec_disk[CONFIG_REC_DISK_NUM] = {0};


/**
 * @Date: 2020-05-07 14:17:37
 * @Description: kB
 * @Return: 
 */
int get_file_size_by_stat(const char *file_name,long long *file_size,long long *file_space)    
{    
	// unsigned long filesize = 0;        
    struct stat statbuff;    
    if(stat(file_name, &statbuff) < 0)
    {    
        STD_print("error error");
        return -1;    
    }
    else
    {   
        if(file_size)
            *file_size = statbuff.st_size;
        if(file_space)
            *file_space =  ((long long)(statbuff.st_blocks))*512;
    }    
    STD_print("debug:%s st_size:%ld st_blksize:%ld  st_blocks:%ld",
        file_name,statbuff.st_size, statbuff.st_blksize,statbuff.st_blocks);
    return 0;

}
int file_test(char *p_path)
{
	unsigned long filesize = -1;        
    struct stat statbuff;    
    if(stat(p_path, &statbuff) < 0)
    {    
        STD_print("");
        return filesize;    
    }
    if(S_ISDIR(statbuff.st_mode)){
        STD_print("%s is dir",p_path);
    }
    STD_print("st_size:%ld st_blksize:%ld  st_blocks:%ld",
        statbuff.st_size, statbuff.st_blksize,statbuff.st_blocks);

    return 0;
}

static const char *_xsd_disk_cat_pattern_local[XSD_DISK_CAT_PATTERN_NUM]  =
{
#if 1   //CONFIG_PLATFORM_X86
	"ata",/*assume PCI chip is local?*/
#else
	"pci",
#endif
	"devices/platform/ahci",
	NULL,
};
static const char *_xsd_disk_cat_pattern_usb[XSD_DISK_CAT_PATTERN_NUM] =
{
	"usb",
	NULL,
};

//added by lipeng@hisome.com 20180130
static const char *_xsd_disk_cat_pattern_sd[XSD_DISK_CAT_PATTERN_NUM] =
{
	"mmc",
	NULL,
};

static int _xsd_disk_get_category(const char *devname/*sda,sdb...*/,xsd_disk_cat_t *dc_p)
{
	char path[64] = "", buf[256] = "";
	int idx;

	*dc_p = XSD_DISK_CAT_UNKNOWN;/*assign default value*/

	snprintf(path,sizeof(path),"/sys/block/%s",devname);

	if((-1)==readlink(path,buf,sizeof(buf)-1))
	{
		xeLOG_ERR("readlink(%s) fail, %s",path,strerror(errno));
		return XEREC_FAIL;
	}

	for(idx=0; idx<XSD_DISK_CAT_PATTERN_NUM; idx++)
	{

		//printf("%s--%s\n",buf,_xsd_disk_cat_pattern_local[idx]);
		if(_xsd_disk_cat_pattern_local[idx]!=NULL \
			&& strstr(buf,_xsd_disk_cat_pattern_local[idx]))
		{
			*dc_p = XSD_DISK_CAT_LOCAL;
			return XEREC_SUCCESS;
		}

		if(_xsd_disk_cat_pattern_usb[idx]!=NULL \
			&& strstr(buf,_xsd_disk_cat_pattern_usb[idx]))
		{
			*dc_p = XSD_DISK_CAT_USB;

			xeLOG_INFO("%s is USB",path);
			return XEREC_SUCCESS;
		}

        //added by lipeng@hisome.com 20180130
        if(_xsd_disk_cat_pattern_sd[idx]!=NULL \
			&& strstr(buf,_xsd_disk_cat_pattern_sd[idx]))
		{
			*dc_p = XSD_DISK_CAT_SD;

			xeLOG_INFO("%s is mmc", path);
			return XEREC_SUCCESS;
		}
        //=================================================
	}

	xeLOG_ERR("%s not Local? not USB? what's it?(%s)",path,buf);
	return XEREC_FAIL;
}


void ltrim (char *s)
{
    char *p;
    p = s;
    while (*p == ' ' || *p == '\t'){
		*p++;
	}
    strcpy (s,p);
} 
// void rtrim (unsigned char *s)
// {
//     int i;
//     i = strlen(s)-2;
//     while ((s[i]==0x10 || s[i]==0x20) && i >= 0) {i--;};
//     s[i+1] = '\0';	
// }
// void trim (char *s)
// {
//     ltrim (s);
//     rtrim (s);
// }
int __xerec_get_disk_devinfo(char *devName, char *SN, char *Model)
{
    struct hd_driveid id;

    int fd = open(devName, O_RDONLY|O_NONBLOCK);
    if (fd < 0)
    {
        fd = open(devName, O_RDONLY|O_NONBLOCK);
        if(fd < 0)
        {
            xeLOG_ERR("open [%s] fail\n", devName);
            return -1;
        }
    }
    if(!ioctl(fd, HDIO_GET_IDENTITY, &id))
    {
        strcpy(SN, (char *)id.serial_no);
		ltrim(SN);
    }
	close(fd);
    return 0;
}


int space_build_harddisk_info()
{
	FILE *procpt = NULL;
	char line[HISOME_LEN_256],ptname[HISOME_LEN_64],diskname[HISOME_LEN_64];
	int ma, mi; 
	long long sz;
    int ret;
	int seq_num;
	xerec_disk_t *xerec_disk_p = NULL;
	xsd_disk_cat_t diskcat = XSD_DISK_CAT_UNKNOWN;

	char raid_exsit = 0;

	if(!access(RAID_DEVICE,F_OK|R_OK|W_OK))
		raid_exsit = 1;

	procpt = fopen(PROC_PARTITIONS, "r");
	if(procpt==NULL){
		xeLOG_ERR("fopen(\"PROC_PARTITIONS\") fail, %s",strerror(errno));
		return -1;
	}

	while (fgets(line, sizeof(line), procpt)) {
		ret = 0;
		memset(ptname,0,sizeof(ptname));
		memset(diskname,0,sizeof(diskname));

		if(_xsd_rec_disk_num==CONFIG_REC_DISK_NUM){
			xeLOG_NOTICE("too many harddisks, only %d support now.",CONFIG_REC_DISK_NUM);
			break;
		}

		if (sscanf (line, " %d %d %llu %[^\n ]", &ma, &mi, &sz, ptname) != 4){
			continue;
		}

		if(raid_exsit){			        //have raid array
            xeLOG_NOTICE("raid_exsit");
		}	
		if(strstr(ptname, "default") != NULL){
			continue;
		}

		if((ma==XSD_HARDDISK_MAJOR || ma==XSD_HARDDISK_MAJOR1 
            || ma==XSD_USBDISK_MAJOR || ma==XSD_SDCARD_MAJOR/*major*/ || ma==254)
             && (mi%8)==0)
		//===================================================
		{
			/*block device name, get it's category*/
			_xsd_disk_get_category(ptname,&diskcat);
			diskcat = XSD_DISK_CAT_LOCAL;
			if(diskcat == XSD_DISK_CAT_LOCAL){
				xeLOG_INFO("Disk(%s) is LOCAL harddisk",ptname);
				seq_num = 0;
			}else{
				xeLOG_INFO("Disk(%s) is not LOCAL harddisk",ptname);
				seq_num = 0;
			}
		}
		else if(diskcat==XSD_DISK_CAT_LOCAL &&	\
			(ma==XSD_HARDDISK_MAJOR || ma==XSD_HARDDISK_MAJOR1)	\
			 && (mi%8)!=0 )
		{
			/*block device partition*/
			if(strcmp(ptname,"sda3")){
				continue;
			}
			// STD_print()
			seq_num++;
			strncpy(diskname,ptname,sizeof(diskname)-1);
			diskname[strlen(diskname)-1] = '\0';

			xerec_disk_p = (xerec_disk_t*)calloc(1,sizeof(*xerec_disk_p));
			if(xerec_disk_p==NULL)
			{
                STD_print("xerec_disk_p is NULL");
                break;
			}

			xerec_disk_p->type = XEREC_DISK_TYPE_HARDDISK;
			xerec_disk_p->file_mode = 0;
			xerec_disk_p->status = 0;
			xerec_disk_p->capacity = sz/1024;

			snprintf(xerec_disk_p->devname,sizeof(xerec_disk_p->devname),"/dev/%s",ptname);
			{
				char sn[128];
				char models[128];
				__xerec_get_disk_devinfo(xerec_disk_p->devname,sn,models);
				snprintf(xerec_disk_p->volume,sizeof(xerec_disk_p->volume)-1,
					"%s_%d",sn,seq_num);
				xeLOG_INFO("dev:%s,volume(sn):%s",xerec_disk_p->devname,xerec_disk_p->volume);
			}


			if(_xsd_rec_disk_num>0)
			{
				_xsd_rec_disk[_xsd_rec_disk_num-1]->next = xerec_disk_p;
			}
			_xsd_rec_disk[_xsd_rec_disk_num] = xerec_disk_p;
			_xsd_rec_disk_num++;
			xeLOG_INFO("\n\tpartition scan seq:%d",_xsd_rec_disk_num);
			xeLOG_INFO("scaned harddisk partition: %s of size %lld GB",xerec_disk_p->devname,xerec_disk_p->capacity/1024);

		}
		else if(diskcat==XSD_DISK_CAT_USB && ma==XSD_USBDISK_MAJOR/*major*/ && (mi%16)!=0 )//fix by quxl@hisome.com 20190424
		{

		}
		else if(diskcat==XSD_DISK_CAT_SD && (ma==XSD_SDCARD_MAJOR/*major*/||ma==254) && (mi%16)!=0)//fix by quxl@hisome.com 20190424
		{

		}
		else
		{
			diskcat = XSD_DISK_CAT_UNKNOWN;
			continue;
		}
	}

	fclose(procpt);
	_xsd_rec_disk_scaned = 1;
	xeLOG_INFO("\n\tpartition scan end...");
	return ret;
}


#define FNAME_FSOK	"ME.isOK.gpt"
static int _xsd_disk_FS_is_OK( xerec_disk_t *xerec_disk_p)
{
	char fpath[256] = "";
	
	snprintf(fpath,sizeof(fpath)-1,"%s/%s",xerec_disk_p->mntdir,FNAME_FSOK);

	if(access(fpath,F_OK)==0 )
	{
		xeLOG_NOTICE("Exist: %s",fpath);
		return 1;
	}

	xeLOG_NOTICE("Not-Exist: %s",fpath);
	return 0;
}
static int _xsd_disk_FS_touch_OK(xerec_disk_t *xerec_disk_p)
{
	char fpath[256] = "";
	int fd;

	snprintf(fpath,sizeof(fpath)-1,"%s/%s",xerec_disk_p->mntdir,FNAME_FSOK);

	fd = creat(fpath,S_IRUSR );
	if(fd==-1)
	{
		xerec_disk_p->status = -1;
		xeLOG_ERR("creat(%s) fail, %s",fpath,strerror(errno));
		return -1;
	}
	close(fd);
	return 0;
}
int _prealloc_space_in_one_harddisk(xerec_disk_t *xerec_disk_p)
{
    int ret = 0;
    int dir_num;
    long long pre_size = 0;
    if(xerec_disk_p->type == XEREC_DISK_TYPE_HARDDISK){
        pre_size =(PER_IPC_SPACE_GB<<10);//100G -> 100K
    }else{
        xeLOG_WARNING("not harddisk,%s",xerec_disk_p->devname);
    }

    if(_xsd_disk_FS_is_OK(xerec_disk_p)){
		//TODO:update mntdir by volume(sn) in space_mgnt_tbl
		//TODO:update mntdir dir by harddisk_sn ipcMgnt
		//TODO:insert into temp ipcMgnt  select * from ipcMgnt by harddisk sn ;
		//TODO:insert into temp space_mgnt_tbl  select * from ipcMgnt by harddisk sn ;
        return 0;
    }

    dir_num = (xerec_disk_p->capacity)/(pre_size)*95/100;  

	t_space_query_info space_res = {0};
	space_res.dir_limit = dir_num;
	space_res.dir_free = dir_num;
	strcpy(space_res.harddisk_dir,xerec_disk_p->mntdir);
	strcpy(space_res.harddisk_sn,xerec_disk_p->volume);

	tiny_rec_update_sysmgntdb_tbl(E_TBL_SPACE,E_INSERT_RECORD,&space_res);
	xeLOG_NOTICE("prealloc files in disk,dev:%s,mntdir:%s,space->dir_limit:%d",
		xerec_disk_p->devname,xerec_disk_p->mntdir,dir_num);
	ret = _xsd_disk_FS_touch_OK(xerec_disk_p);
	if(ret==-1){
		xeLOG_ERR("DISK(%s) auto FS touch OK fail.",xerec_disk_p->devname);
		return -1;
	}
	return ret;
}

int xerec_disk_mount(xerec_disk_t *xerec_disk_p,const char *mnt_dir)
{
	char mdir[64], *cptr;

	memset(mdir,0,sizeof(mdir));
	if(mnt_dir){
		strncpy(mdir,mnt_dir,sizeof(mdir)-1);
	}
	else
	{
		cptr = strrchr(xerec_disk_p->devname,'/');
		if(!cptr)
		{
			cptr = xerec_disk_p->devname;
		}
		else
		{
			cptr++;
		}

		snprintf(mdir,sizeof(mdir),"/mnt/%s",cptr);
		strcpy(xerec_disk_p->mntdir,mdir);
	}

	return 0;
}

int space_build_rec_info()
{
	int ret;

	xerec_disk_t *xerec_disk_p;
    xerec_disk_p = _xsd_rec_disk[0];

	do
	{
		if(xerec_disk_p==NULL)
			break;
#ifndef CONFIG_PLATFORM_UBUNTU
		ret = xerec_disk_mount(xerec_disk_p,NULL);
#else
		strcpy(xerec_disk_p->mntdir,"/data");
		strcpy(xerec_disk_p->volume,"123");
#endif
		xeLOG_NOTICE( "Initializing... dev:%s,mnt:%s", xerec_disk_p->devname,xerec_disk_p->mntdir);
		ret = _prealloc_space_in_one_harddisk(xerec_disk_p);
		if(ret==-1)
		{
			xeLOG_ERR("auto rec disk(%s) fail, error=%d",xerec_disk_p->devname,xerec_disk_p->error);
		}

		xerec_disk_p = xerec_disk_p->next;
	}while(0x20200509);
	//TODO: TODO:insert into  ipcMgnt  select * from tmp  ipcMgnt by harddisk sn
	//TODO: TODO:insert into  space_mgnt_tbl  select * from tmp space_mgnt_tbl by harddisk sn
	return ret;
}


int space_alloc_dir_for_new_device(t_space_query_info *p_space_info)
{
	int  ret = -1;
	xerec_disk_t *xerec_disk_p;
    xerec_disk_p = _xsd_rec_disk[0];
	do
	{
		t_space_query_info space_res = {0};

		if(xerec_disk_p==NULL)
			break;

		strcpy(space_res.harddisk_dir,xerec_disk_p->mntdir);
		tiny_rec_query_sysmgntdb_info(E_TBL_SPACE,&space_res);
		if(space_res.dir_free > 0){
			xeLOG_NOTICE("prepare space for new device success,dir_free:%d,dir_limit:%d",
				space_res.dir_free,space_res.dir_limit);
			space_res.dir_free--;
			space_res.dir_used++;
			tiny_rec_update_sysmgntdb_tbl(E_TBL_SPACE,E_UPDATE_RECORD,&space_res);
			memcpy(p_space_info,&space_res,sizeof(t_space_query_info));
			ret = 0;
			break;
		}else{
			xeLOG_NOTICE("prepare space for new device failed in  %s", xerec_disk_p->mntdir);
		}
		xerec_disk_p = xerec_disk_p->next;
	}while(0x20200509);

	return ret;
}

int tiny_space_init()
{
	int ret;
	ret = space_build_harddisk_info();
	ret = space_build_rec_info();
	return ret;
}


